package com.xisoft.devise.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xisoft.base.entity.ReferEntity;
import com.xisoft.base.page.PageResult;
import com.xisoft.base.page.Query;
import com.xisoft.base.service.XfServiceImpl;
import com.xisoft.common.bean.BeanHelper;
import com.xisoft.common.bean.BeanUtil;
import com.xisoft.common.constant.IPubCons;
import com.xisoft.common.db.SqlHelper;
import com.xisoft.common.io.FileUtilbc;
import com.xisoft.common.io.StreamUtil;
import com.xisoft.common.pubEnv.DateUtilbc;
import com.xisoft.common.pubEnv.JsonUtil;
import com.xisoft.common.pubEnv.PubEnvUtil;
import com.xisoft.common.pubEnv.StringUtil;
import com.xisoft.devise.config.template.GeneratorConfig;
import com.xisoft.devise.config.template.GeneratorInfo;
import com.xisoft.devise.entity.GenModel;
import com.xisoft.devise.entity.TableColEntity;
import com.xisoft.devise.entity.TableEntity;
import com.xisoft.devise.entity.TemplateInfo;
import com.xisoft.devise.mapper.IGeneratorMapper;
import com.xisoft.devise.service.IGenService;
import com.xisoft.devise.utils.GenUtils;
import com.xisoft.generator.utils.ResultEntity;
import com.xisoft.utils.SpringHelper;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;

/**
 * *
 * Created with Description:
 *
 * @version 1.0 <br>
 * @packagename: com.xisoft.generator.service.impl<br>
 * @author: LiBencheng <br>
 * @computer: licheng <br>
 * @date: Created on 2022/8/9 13:56 <br>
 */
@Service ("GenServiceImpl")
@Transactional (rollbackFor = Exception.class)
public class GenServiceImpl extends XfServiceImpl implements IGenService
{
    private String TABLE = "table";
    private String NAME = "name";
    private String CHILD = "child";
    @Autowired
    private IGeneratorMapper genMapper;
    @Autowired
    private GeneratorConfig generatorConfig;

    @Override public ResultEntity genCodeBytable(String json) throws Exception
    {
        ResultEntity rest = new ResultEntity();
        Map< String,Object > param = JsonUtil.toMap(json);
        String mdCode = StringUtil.toString(param.get("moduleCode"));
        String tables = StringUtil.toString(param.get("tableName"));
        String[] tableStr = tables.split(IPubCons.COMMA);
        StringBuffer msg = new StringBuffer();
        for (int i = 0; i < PubEnvUtil.getSize(tableStr); i++)
        {
            if (PubEnvUtil.isEmpty(tableStr[i])) { continue; }
            String table = tableStr[i].trim();

            Map< String,Object > tableMap = SpringHelper.getBean(MetadataServiceImpl.class).getSysTabByTable2(table);
            if (PubEnvUtil.getSize(tableMap) > 0)
            { msg.append(makeCode(tableMap, mdCode)).append(IPubCons.CRLF); }
            else { msg.append("这个table（").append(table).append("）数据库没有查到对应的数据！\n"); }
        }
        rest.put("msg", StringUtil.toString(msg));

        return rest;
    }

    @Override public ResultEntity makeCode(String tableJson) throws Exception
    {
        ResultEntity resultEntity = new ResultEntity();
        // tableJson = "{'table':{'name':'HR_SALARY_DATA','child':[{'table':{'name':'HR_SALARY_DATA_DETAILS'}}]}}";
        // Map< String,Object > valMap = JSONObject.parseObject(tableJson);
        String filePath = this.getClass().getResource("/json/").getPath();
        List< File > files = FileUtilbc.listFile(new File(filePath));
        for (File file : files)
        {
            // if (PubEnvUtil.equals("hr_arrears_rules.json", file.getName()))
            if (file.getName().endsWith(".json"))
            {
                tableJson = StreamUtil.InputStreamTOString(StreamUtil.getFileInputStream(file));
                Map< String,Object > valMap = JsonUtil.toMap(tableJson);

                makeCode(valMap, null);
                // SpringHelper.getBean(MetadataServiceImpl.class).savaScript(tableJson);
                new MetadataServiceImpl().savaScript(tableJson);
            }
        }
        return resultEntity;
    }


    /************************************************************* <br>
     * ParallelMethodsMustNotDefineGroupConversionForCascadedReturnValue
     *说明: <br>
     *
     * @Description   <br>
     * @Date Created on 2022/9/26  13:54  <br>
     * @param tableMap
     * @param tableInfo
     * @param structList
     * @param setRefList <br>
     * @return java.util.List<com.xisoft.devise.entity.TableColEntity>  <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    private List< TableColEntity > makeTableColEntity(Map< String,Object > tableMap
            , TableEntity tableInfo, List< String > structList, List< String > setRefList) throws Exception
    {
        List< Map< String,Object > > toList = (List< Map< String,Object > >) tableMap.get("fields");
        List< TableColEntity > tableColEntitys = new LinkedList<>();
        TableColEntity tableColEntity = null;
        for (int i = 0; i < PubEnvUtil.getSize(toList); i++)
        {
            Map< String,Object > fieldMap = toList.get(i);
            tableColEntity = new TableColEntity();
            tableColEntity.setTablename(tableInfo.getTablename());
            tableColEntity.setTablecomments(tableInfo.getTablecomments());
            tableColEntity.setColumnname(StringUtil.toString(fieldMap.get("sdf_field_en_name")));
            tableColEntity.setColumncomments(StringUtil.toString(fieldMap.get("sdf_field_zh_name")));
            tableColEntity.setDataType(StringUtil.toString(fieldMap.get("sdf_field_type")));
            tableColEntity.setDatalength(StringUtil.toString(fieldMap.get("sdf_field_length")));
            tableColEntity.setDatascale(StringUtil.toString(fieldMap.get("decimalprecision")));
            tableColEntity.setDataprecision(tableColEntity.getDatascale());
            tableColEntity.setNullable(StringUtil.toString(fieldMap.get("isnotnull")));
            tableColEntity.setIsRefer(StringUtil.toString(fieldMap.get("isRefer")));
            tableColEntity.setRefobject(fieldMap.get("refobject"));

            if (PubEnvUtil.equals(PubEnvUtil.NO
                    , StringUtil.toString(fieldMap.get("sdf_primary_key")).toLowerCase(Locale.ROOT)))
            {
                tableColEntity.setPk(tableColEntity.getColumnname());
                tableColEntity.setIsPK(Boolean.TRUE);
            }

            setRef(structList, setRefList, tableColEntity.getColumnname()
                    , tableColEntity.getColumncomments()
                    , fieldMap.get("refobject"));

            tableColEntitys.add(tableColEntity);
        }

        return tableColEntitys;
    }

    /************************************************************* <br>
     *
     *说明: vo类 参照属性set方法 <br>
     *
     * @Description   <br>
     * @Date Created on 2022/9/26  13:53  <br>
     * @param structList
     * @param setRefList
     * @param colum
     * @param comments
     * @param refObj <br>
     * @return void  <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    private void setRef(List< String > structList, List< String > setRefList
            , String colum, String comments, Object refObj)
    {
        if (PubEnvUtil.isNotEmptyObj(refObj))
        {
            StringBuffer setMethodStr = new StringBuffer();
            Map< String,Object > refMap = (Map< String,Object >) refObj;
            ReferEntity refEntity = BeanUtil.parseVO(refMap, ReferEntity.class);
            CheckUtil.checkRefObj(refEntity);
            colum = colum.toLowerCase(Locale.ROOT);

            setMethodStr.append("    /*************************************** <br>").append(IPubCons._N);
            setMethodStr.append("     *说明: ").append(comments).append("<br>").append(IPubCons._N);
            setMethodStr.append("     * @Date Created on");
            setMethodStr.append(DateUtilbc.currentDateTime()).append(" <br>").append(IPubCons._N);
            setMethodStr.append("     * @param ").append(colum).append(" <br>").append(IPubCons._N);
            setMethodStr.append("     * @return void  <br>").append(IPubCons._N);
            setMethodStr.append("     * @author LIBENCHENG").append(IPubCons._N);
            setMethodStr.append("     * @version 1.0 <br>").append(IPubCons._N);
            setMethodStr.append("    ***************************************/").append(IPubCons._N);
            setMethodStr.append("    public void set").append(StringUtil.firstCharUpperCase(colum));
            setMethodStr.append("(com.xisoft.base.entity.ReferEntity ").append(colum).append("){").append(IPubCons._N);
            setMethodStr.append("        if (null == ").append(colum).append("){").append(IPubCons._N);
            setMethodStr.append("            ").append(colum);
            setMethodStr.append(" = new com.xisoft.base.entity.ReferEntity();").append(IPubCons._N);
            setMethodStr.append("            ").append(colum).append(".setId(\"");
            setMethodStr.append(StringUtil.valueOfEmpty(refEntity.getId())).append("\");").append(IPubCons._N);
            setMethodStr.append("            ").append(colum).append(".setTableName(\"");
            setMethodStr.append(StringUtil.valueOfEmpty(refEntity.getTableName())).append("\");").append(IPubCons._N);
            setMethodStr.append("            ").append(colum).append(".setPkName(\"");
            setMethodStr.append(StringUtil.valueOfEmpty(refEntity.getPkName())).append("\");").append(IPubCons._N);
            setMethodStr.append("            ").append(colum).append(".setFieldName(\"");
            setMethodStr.append(StringUtil.valueOfEmpty(refEntity.getFieldName())).append("\");").append(IPubCons._N);
            setMethodStr.append("            ").append(colum).append(".setDisplayName(\"");
            setMethodStr.append(StringUtil.valueOfEmpty(refEntity.getDisplayName())).append("\");").append(IPubCons._N);
            setMethodStr.append("        }").append(IPubCons._N);
            setMethodStr.append("        this.").append(colum).append(" = ").append(colum);
            setMethodStr.append(IPubCons.COMMA).append(IPubCons._N);
            setMethodStr.append("    }").append(IPubCons._N);

            setRefList.add(StringUtil.valueOf(setMethodStr));
            structList.add("        set" + StringUtil.firstCharUpperCase(colum) + "(null);");
        }
    }


    private TableEntity makeTableEntity(Map< String,Object > tableMap) throws Exception
    {
        TableEntity tableInfo = new TableEntity();
        tableInfo.setCode(StringUtil.toString(tableMap.get("sdt_table_en_name")));
        tableInfo.setTablename(tableInfo.getCode());
        String classname = getClassName(tableInfo.getCode().toLowerCase());
        tableInfo.setClassname(classname);
        tableInfo.setTablecomments(StringUtil.toString(tableMap.get("sdt_table_zh_name")));
        tableInfo.setCreatetime(DateUtilbc.currentDateTime());
        tableInfo.setTabletype(StringUtil.toString(tableMap.get("sdt_table_type")));

        return tableInfo;
    }

    public static String getClassName(String str)
    {
        StringBuffer sb = new StringBuffer();
        String[] subStr = str.split(IPubCons.UNDERSCORE);
        for (int i = 1; i < PubEnvUtil.getSize(subStr); i++)
        { sb.append(StringUtil.firstCharUpperCase(subStr[i])); }

        return StringUtil.toString(sb);
    }

    /************************************************************* <br>
     *
     *说明: <br>
     *
     * @Description   <br>
     * @Date Created on 2022/9/26  13:57  <br>
     * @param tableMap <br>
     * @return void  <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    private String makeCode(Map< String,Object > tableMap, String mdCode) throws Exception
    {
        StringBuffer msg = new StringBuffer();
        List< String > setRef = new LinkedList<>();
        List< String > structStr = new LinkedList<>();
        TableEntity tableInfo = makeTableEntity(tableMap);
        List< TableColEntity > tableCols = makeTableColEntity(tableMap, tableInfo, structStr, setRef);
        if (PubEnvUtil.isNotEmptyObj(tableInfo))
        {
            GenModel genModel = new GenModel();
            if (!PubEnvUtil.isEmpty(mdCode))
            { genModel.setModuleName(mdCode); }
            // genModel.setSetRef(setRef);
            // genModel.setStruct(structStr);
            genModel.setTableComments(tableInfo.getTablecomments());
            //表信息
            genModel.setTableName(tableInfo.getTablename());
            genModel.setClassName(tableInfo.getClassname());
            genModel.setColumnList(tableCols);
            //主键
            tableCols.stream().forEach(tableField ->
                                       {
                                           tableField.setVtypeByDType(genMapper);
                                           if (PubEnvUtil.equals(PubEnvUtil.TRUE, tableField.getIsPK()))
                                           { genModel.setPk(tableField.getPk()); }
                                       });

            // if (!PubEnvUtil.isEmptyObj(childTable))
            { genModel.setChildTables(null); }

            //代码生成器信息
            GeneratorInfo generator = generatorConfig.getGeneratorConfig();

            //渲染模板并输出
            for (TemplateInfo template : generator.getTemplates())
            {
                if (PubEnvUtil.equals("Engine.java.ftl", template.getTemplateName()))
                { continue; }
                genModel.setTemplateName(template.getTemplateName());
                Map< String,Object > bean2Map = BeanHelper.transBean2Map(genModel);
                bean2Map.put("package", genModel.getPackageName());
                String content = GenUtils.getTemplateContent(template.getTemplateContent(), bean2Map);
                String path = GenUtils.getTemplateContent(template.getGeneratorPath(), bean2Map);

                // if (PubEnvUtil.unEquals(IPubCons.ONE, tableMap.get("type"))
                //         && PubEnvUtil.equals("Entity.java.ftl", template.getTemplateName()))
                // { FileUtils.writeStringToFile(new File(path), content, "utf-8"); }
                // else if (PubEnvUtil.equals(IPubCons.ONE, tableMap.get("type")))
                { FileUtils.writeStringToFile(new File(path), content, "utf-8"); }

                msg.append("生成代码路径：").append(path).append(IPubCons.CRLF);
            }
            System.out.println(msg);
        }

        return StringUtil.toString(msg);
    }

    @Override public List< TableColEntity > getFieldList(String tableName) throws Exception
    { return genMapper.getFieldList(SqlHelper.getColumnByTableOrcl(tableName)); }

    @Override
    public PageResult< TableEntity > page(Query query) throws Exception
    {
        Page< TableEntity > page = new Page<>(query.getPage(), query.getLimit());
        QueryWrapper< TableEntity > wrapper = new QueryWrapper<>();
        IPage< TableEntity > ipage =
                genMapper.selectPage(SqlHelper.queryTableByOrcl(query.getTableName()), page, wrapper);
        return new PageResult<>(page.getRecords(), page.getTotal());
    }

    @Override public ResultEntity genCode(String tableName) throws Exception
    { return handleCode(tableName, new LinkedList<>()); }

    @Override public ResultEntity createCode(String tableJson) throws Exception
    {
        ResultEntity resultEntity = new ResultEntity();
        // tableJson = "{'table':{'name':'HR_SALARY_DATA','child':[{'table':{'name':'HR_SALARY_DATA_DETAILS'}}]}}";
        // Map< String,Object > valMap = JSONObject.parseObject(tableJson);
        Map< String,Object > valMap = JsonUtil.toMap(tableJson);
        handleCode((Map< String,Object >) valMap.get(TABLE));
        return resultEntity;
    }

    /************************************************************* <br>
     *
     *说明: 处理代码<br>
     *
     * @Description   <br>
     * @Date Created on 2022/8/16  11:02  <br>
     * @param tableMap
     * @return com.xisoft.generator.utils.ResultEntity  <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    private void handleCode(Map< String,Object > tableMap) throws Exception
    {
        List< String > childTable = new LinkedList<>();
        List< Map< String,Object > > childList = (List< Map< String,Object > >) tableMap.get(CHILD);
        if (PubEnvUtil.isNotEmptyObj(childList))
        {
            childList.stream().forEach(child ->
                                       {
                                           Map< String,Object > childMap = (Map< String,Object >) child.get(TABLE);
                                           if (PubEnvUtil.isNotEmptyObj(childMap))
                                           {
                                               String str = "";
                                               String[] strs = StringUtil.valueOf(childMap.get(NAME)).toLowerCase()
                                                                         .split(PubEnvUtil.UNDERSCORE);
                                               for (int i = 1; i < PubEnvUtil.getSize(strs); i++)
                                               {
                                                   str += StringUtil.firstCharUpperCase(strs[i]);
                                                   System.out.println(StringUtil.firstCharUpperCase(strs[i]));
                                               }
                                               childTable.add(str);
                                           }
                                       });
        }

        handleCode(StringUtil.valueOf(tableMap.get(NAME)), childTable);
        if (PubEnvUtil.isNotEmptyObj(childList))
        {
            childList.stream().forEach(child ->
                                       {
                                           try
                                           {
                                               Map< String,Object > childMap = (Map< String,Object >) child.get(TABLE);
                                               if (PubEnvUtil.isNotEmptyObj(childMap))
                                               { handleCode(childMap); }
                                           }
                                           catch (Exception e)
                                           {
                                               throw new RuntimeException(e);
                                           }
                                       });
        }

    }

    /************************************************************* <br>
     *
     *说明: 处理代码<br>
     *
     * @Description   <br>
     * @Date Created on 2022/8/16  11:02  <br>
     * @param tableName
     * @param childTable <br>
     * @return com.xisoft.generator.utils.ResultEntity  <br>
     * @Author LIBENCHENG
     * @version 1.0 <br>
     ************************************************************* <br>
     */
    private ResultEntity handleCode(String tableName, List< String > childTable) throws Exception
    {
        List< TableColEntity > tableCols = genMapper.getFieldList(SqlHelper.getColumnByTableOrcl(tableName));
        TableEntity tableInfo = genMapper.getTableInfo(tableName);
        if (PubEnvUtil.isNotEmptyObj(tableInfo))
        {
            GenModel genModel = new GenModel();
            genModel.setTableComments(StringUtil.valueOfZero(tableInfo.getTablecomments()));
            //表信息
            genModel.setTableName(tableName);
            genModel.setClassName(tableInfo.getClassname());
            genModel.setColumnList(tableCols);
            //主键
            tableCols.stream().forEach(tableField ->
                                       {
                                           tableField.setVtypeByDType(genMapper);
                                           if (PubEnvUtil.equals(PubEnvUtil.TRUE, tableField.getPk()))
                                           { genModel.setPk(tableField.getPk()); }
                                       });

            // if (!PubEnvUtil.isEmptyObj(childTable))
            { genModel.setChildTables(childTable); }

            //代码生成器信息
            GeneratorInfo generator = generatorConfig.getGeneratorConfig();

            //渲染模板并输出
            for (TemplateInfo template : generator.getTemplates())
            {
                if (PubEnvUtil.equals("Engine.java.ftl", template.getTemplateName()))
                { continue; }
                genModel.setTemplateName(template.getTemplateName());
                Map< String,Object > bean2Map = BeanHelper.transBean2Map(genModel);
                bean2Map.put("package", genModel.getPackageName());
                String content = GenUtils.getTemplateContent(template.getTemplateContent(), bean2Map);
                String path = GenUtils.getTemplateContent(template.getGeneratorPath(), bean2Map);
                //FileUtil.writeUtf8String(content, path);
                FileUtils.writeStringToFile(new File(path), content, "utf-8");
                System.out.println("生成代码路径：" + path);
            }
        }
        return null;
    }
}
